"""
图片处理模块 - 完整修复版本
负责图片的加载、处理和剪贴板操作
"""

import os
import logging
import tempfile
import shutil
from typing import Optional, Tuple, Dict, Any
from PIL import Image, ImageTk
from io import BytesIO

try:
    import win32clipboard
    WIN32_AVAILABLE = True
except ImportError:
    WIN32_AVAILABLE = False

logger = logging.getLogger(__name__)


class ImageProcessor:
    """图片处理器 - 完整修复版本"""

    def __init__(self):
        self.current_image_path: Optional[str] = None
        self.current_image_data: Optional[bytes] = None
        self.preview_image: Optional[ImageTk.PhotoImage] = None
        self._temp_files = []  # 跟踪临时文件，防止资源泄漏

    def load_image(self, image_path: str) -> bool:
        """加载图片文件 - 修复版本"""
        try:
            if not os.path.exists(image_path):
                logger.error(f"图片文件不存在: {image_path}")
                return False

            # 验证图片文件
            if not self.validate_image(image_path):
                logger.error(f"图片文件验证失败: {image_path}")
                return False

            # 验证图片格式和内容
            try:
                with Image.open(image_path) as img:
                    # 尝试读取图片数据以验证完整性
                    img.verify()
            except Exception as e:
                logger.error(f"图片格式无效或已损坏: {e}")
                return False

            # 重新打开图片（verify会关闭图片）
            with Image.open(image_path) as img:
                # 转换为RGB模式以确保兼容性
                if img.mode != 'RGB':
                    img = img.convert('RGB')

                # 保存图片数据
                output = BytesIO()
                img.save(output, format='PNG')  # 使用PNG格式保存以保证质量
                self.current_image_data = output.getvalue()
                output.close()

            self.current_image_path = image_path
            logger.info(f"图片加载成功: {image_path} (尺寸: {img.size}, 模式: {img.mode})")
            return True

        except Exception as e:
            logger.error(f"加载图片失败: {e}")
            return False

    def copy_image_to_clipboard(self, image_path: Optional[str] = None) -> bool:
        """将图片复制到剪贴板 - 完整修复版本"""
        if not WIN32_AVAILABLE:
            logger.error("win32clipboard 不可用，无法复制图片到剪贴板")
            return False

        target_path = image_path or self.current_image_path
        if not target_path or not os.path.exists(target_path):
            logger.error(f"图片路径无效: {target_path}")
            return False

        try:
            # 使用临时文件确保图片格式正确
            temp_file = None
            try:
                with Image.open(target_path) as image:
                    # 确保图片为RGB模式
                    if image.mode != 'RGB':
                        image = image.convert('RGB')

                    # 创建临时文件保存转换后的图片
                    temp_fd, temp_file = tempfile.mkstemp(suffix='.bmp')
                    os.close(temp_fd)
                    image.save(temp_file, "BMP")
                    self._temp_files.append(temp_file)

                # 读取BMP文件数据
                with open(temp_file, 'rb') as f:
                    bmp_data = f.read()

                # 移除BMP文件头 (14字节)
                if len(bmp_data) >= 14 and bmp_data[:2] == b'BM':
                    dib_data = bmp_data[14:]
                else:
                    logger.warning("非标准BMP格式，尝试直接使用数据")
                    dib_data = bmp_data

                # 复制到剪贴板
                win32clipboard.OpenClipboard()
                try:
                    win32clipboard.EmptyClipboard()
                    win32clipboard.SetClipboardData(win32clipboard.CF_DIB, dib_data)
                    logger.info(f"图片已复制到剪贴板: {os.path.basename(target_path)}")
                    return True
                except Exception as e:
                    logger.error(f"设置剪贴板数据失败: {e}")
                    return False
                finally:
                    try:
                        win32clipboard.CloseClipboard()
                    except Exception as e:
                        logger.error(f"关闭剪贴板失败: {e}")

            finally:
                # 清理临时文件
                if temp_file and os.path.exists(temp_file):
                    try:
                        os.unlink(temp_file)
                        if temp_file in self._temp_files:
                            self._temp_files.remove(temp_file)
                    except Exception as e:
                        logger.warning(f"清理临时文件失败: {e}")

        except Exception as e:
            logger.error(f"复制图片到剪贴板失败: {e}")
            return False

    def copy_loaded_image_to_clipboard(self) -> bool:
        """将已加载的图片复制到剪贴板"""
        if not self.current_image_path:
            logger.error("没有已加载的图片")
            return False
        return self.copy_image_to_clipboard(self.current_image_path)

    def get_preview_image(self, size: Tuple[int, int] = (100, 100)) -> Optional[ImageTk.PhotoImage]:
        """获取预览图片 - 修复版本"""
        if not self.current_image_path:
            return None

        try:
            with Image.open(self.current_image_path) as image:
                # 创建缩略图
                image.thumbnail(size, Image.Resampling.LANCZOS)

                # 确保图片模式兼容Tkinter
                if image.mode not in ['RGB', 'RGBA']:
                    image = image.convert('RGB')

                self.preview_image = ImageTk.PhotoImage(image)
                return self.preview_image

        except Exception as e:
            logger.error(f"生成预览图片失败: {e}")
            return None

    def get_image_info(self) -> Optional[Dict[str, Any]]:
        """获取图片信息 - 修复版本"""
        if not self.current_image_path:
            return None

        try:
            with Image.open(self.current_image_path) as img:
                file_size = os.path.getsize(self.current_image_path)
                file_size_mb = file_size / (1024 * 1024)

                return {
                    'path': self.current_image_path,
                    'filename': os.path.basename(self.current_image_path),
                    'size_bytes': file_size,
                    'size_mb': round(file_size_mb, 2),
                    'dimensions': img.size,
                    'width': img.width,
                    'height': img.height,
                    'format': img.format,
                    'mode': img.mode,
                    'is_loaded': True
                }
        except Exception as e:
            logger.error(f"获取图片信息失败: {e}")
            return None

    def get_image_name(self) -> str:
        """获取图片文件名"""
        if self.current_image_path:
            return os.path.basename(self.current_image_path)
        return ""

    def get_image_dimensions(self) -> Optional[Tuple[int, int]]:
        """获取图片尺寸"""
        info = self.get_image_info()
        return info.get('dimensions') if info else None

    def resize_image(self, new_size: Tuple[int, int], output_path: Optional[str] = None) -> bool:
        """调整图片尺寸"""
        if not self.current_image_path:
            return False

        try:
            with Image.open(self.current_image_path) as img:
                # 保持宽高比
                img.thumbnail(new_size, Image.Resampling.LANCZOS)

                output_path = output_path or self.current_image_path
                img.save(output_path)

                logger.info(f"图片已调整尺寸: {new_size}")
                return True

        except Exception as e:
            logger.error(f"调整图片尺寸失败: {e}")
            return False

    def convert_image_format(self, new_format: str, output_path: Optional[str] = None) -> bool:
        """转换图片格式"""
        if not self.current_image_path:
            return False

        try:
            with Image.open(self.current_image_path) as img:
                output_path = output_path or f"{os.path.splitext(self.current_image_path)[0]}.{new_format.lower()}"

                # 确保RGB模式用于JPEG
                if new_format.upper() == 'JPEG' and img.mode != 'RGB':
                    img = img.convert('RGB')

                img.save(output_path, format=new_format.upper())

                logger.info(f"图片已转换为 {new_format} 格式")
                return True

        except Exception as e:
            logger.error(f"转换图片格式失败: {e}")
            return False

    def clear_image(self) -> None:
        """清除当前图片 - 修复版本"""
        self.current_image_path = None
        self.current_image_data = None
        self.preview_image = None

        # 清理临时文件
        for temp_file in self._temp_files:
            try:
                if os.path.exists(temp_file):
                    os.unlink(temp_file)
            except Exception as e:
                logger.warning(f"清理临时文件失败 {temp_file}: {e}")

        self._temp_files.clear()
        logger.info("已清除当前图片和临时文件")

    def validate_image(self, image_path: str) -> bool:
        """验证图片文件 - 修复版本"""
        try:
            if not os.path.exists(image_path):
                logger.error(f"图片文件不存在: {image_path}")
                return False

            # 检查文件大小（限制为20MB）
            max_size_mb = 20
            file_size = os.path.getsize(image_path)
            if file_size > max_size_mb * 1024 * 1024:
                logger.error(f"图片文件过大: {file_size/(1024*1024):.2f}MB > {max_size_mb}MB")
                return False

            # 检查文件扩展名
            allowed_extensions = {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff', '.webp'}
            file_ext = os.path.splitext(image_path)[1].lower()
            if file_ext not in allowed_extensions:
                logger.error(f"不支持的图片格式: {file_ext}")
                return False

            # 验证图片内容
            try:
                with Image.open(image_path) as img:
                    img.verify()  # 验证图片完整性

                    # 检查图片尺寸
                    if img.width == 0 or img.height == 0:
                        logger.error("图片尺寸无效")
                        return False

                    # 检查图片模式
                    if img.mode not in ['1', 'L', 'P', 'RGB', 'RGBA', 'CMYK', 'YCbCr', 'LAB', 'HSV', 'I', 'F']:
                        logger.warning(f"不常见的图片模式: {img.mode}")

                return True

            except Exception as e:
                logger.error(f"图片内容验证失败: {e}")
                return False

        except Exception as e:
            logger.error(f"验证图片失败: {e}")
            return False

    def is_image_loaded(self) -> bool:
        """是否有图片已加载"""
        return self.current_image_path is not None and os.path.exists(self.current_image_path)

    def get_supported_formats(self) -> list:
        """获取支持的图片格式"""
        return ['PNG', 'JPEG', 'GIF', 'BMP', 'TIFF', 'WEBP']

    def create_thumbnail(self, size: Tuple[int, int] = (64, 64),
                        output_path: Optional[str] = None) -> Optional[str]:
        """创建缩略图"""
        if not self.current_image_path:
            return None

        try:
            with Image.open(self.current_image_path) as img:
                # 创建缩略图
                img.thumbnail(size, Image.Resampling.LANCZOS)

                # 生成输出路径
                if not output_path:
                    base_name = os.path.splitext(self.current_image_path)[0]
                    output_path = f"{base_name}_thumbnail.png"

                img.save(output_path, "PNG")
                logger.info(f"缩略图已创建: {output_path}")
                return output_path

        except Exception as e:
            logger.error(f"创建缩略图失败: {e}")
            return None

    def get_image_statistics(self) -> Optional[Dict[str, Any]]:
        """获取图片统计信息"""
        if not self.current_image_path:
            return None

        try:
            with Image.open(self.current_image_path) as img:
                # 转换为RGB进行计算
                rgb_img = img.convert('RGB')

                # 获取像素数据
                pixels = list(rgb_img.getdata())
                total_pixels = len(pixels)

                if total_pixels == 0:
                    return None

                # 计算平均颜色
                avg_red = sum(p[0] for p in pixels) // total_pixels
                avg_green = sum(p[1] for p in pixels) // total_pixels
                avg_blue = sum(p[2] for p in pixels) // total_pixels

                return {
                    'total_pixels': total_pixels,
                    'average_color': (avg_red, avg_green, avg_blue),
                    'file_size': os.path.getsize(self.current_image_path),
                    'file_size_mb': round(os.path.getsize(self.current_image_path) / (1024 * 1024), 2)
                }

        except Exception as e:
            logger.error(f"获取图片统计信息失败: {e}")
            return None

    def __del__(self):
        """析构函数 - 确保资源清理"""
        try:
            self.clear_image()
        except Exception as e:
            logger.warning(f"析构函数清理失败: {e}")